#include "monitor.h"
#include "helper.h"
#include "watchpoint.h"
#include <stdlib.h>
/* The assembly code of instructions executed is only output to the screen
 * when the number of instructions executed is less than this value.
 * This is useful when you use the `si' command.
 * You can modify this value as you want.
 */

// 表示在输出指令时，最大要打印的指令数目。这是用于在调试模式下限制输出的指令数量
#define MAX_INSTR_TO_PRINT 10

// 用于跟踪模拟器的状态。
// 可能的状态包括 STOP、RUNNING 和 END，
// 表示模拟器停止、正在运行和已经结束
int temu_state = STOP;

void exec(uint32_t);

// 用于存储汇编指令
char assembly[80];
// 用于构建包含二进制指令和汇编指令的输出字符串
char asm_buf[128];

// 用于将给定地址处的二进制指令打印为格式化的字符串
void print_bin_instr(uint32_t pc)
{
	int i;
	int l = sprintf(asm_buf, "%8x:   ", pc);
	for (i = 3; i >= 0; i--)
	{
		l += sprintf(asm_buf + l, "%02x ", instr_fetch(pc + i, 1));
	}
	sprintf(asm_buf + l, "%*.s", 8, "");
}

/* Simulate how the MiniMIPS32 CPU works. */
void cpu_exec(volatile uint32_t n)
{
	// 首先，它检查 temu_state 是否为 END
	// 如果是，表示程序已经结束执行，会打印一条相应的消息，并直接返回
	uint32_t pc;
	if (temu_state == END)
	{
		printf("Program execution has ended. To restart the program, exit TEMU and run again.\n");
		return;
	}
	// 如果不是 END 状态，它将 temu_state 设置为 RUNNING，表示模拟器正在运行
	temu_state = RUNNING;

#ifdef DEBUG
	volatile uint32_t n_temp = n;
#endif

	for (; n > 0; n--)
	{
		// 将 cpu.pc 的最高位清零，以将虚拟地址映射到物理地址
		pc = cpu.pc & 0x7FFFFFFF; // map the virtual address to the physical address, e.g. the highest bit in cpu.pc are cleared

#ifdef DEBUG
		uint32_t pc_temp = pc;
		if ((n & 0xffff) == 0)
		{

			fputc('.', stderr);
		}
#endif

		/* Execute one instruction, including instruction fetch,
		 * instruction decode, and the actual execution. */
		exec(pc);
		// 将 cpu.pc 增加4，以指向下一条指令
		cpu.pc += 4;

// 如果启用了调试模式 (#ifdef DEBUG)，则会输出二进制指令和汇编指令的信息，并在日志中记录
#ifdef DEBUG
		print_bin_instr(pc_temp);
		strcat(asm_buf, assembly);
		Log_write("%s\n", asm_buf);
		if (n_temp < MAX_INSTR_TO_PRINT)
		{
			printf("%s\n", asm_buf);
		}
#endif

		/* TODO: check watchpoints here. */
		WP *head = returnhead();
		WP *temp = head->next;
		while (temp != NULL)
		{
			int *success;
			success = (int *)malloc(sizeof(int));
			*success = true;
			uint32_t result = expr(temp->str, success);
			if (result == temp->expr)
			{
				temp = temp->next;
				free(success);
				continue;
			}
			else
			{
				temu_state = STOP;
				printf("a watchpoint has changed:\n");
				printf("previous:\t%d\t%s\t0x%08x\t%d\n", temp->NO, temp->str, temp->expr, temp->expr);
				printf("now:\t\t%d\t%s\t0x%08x\t%d\n", temp->NO, temp->str, result, result);
				free(success);
				temp = temp->next;
				// break;
			}
		}

		if (temu_state != RUNNING)
		{
			return;
		}
	}

	if (temu_state == RUNNING)
	{
		temu_state = STOP;
	}
}
